//go:build !notmpfiles
// +build !notmpfiles

// Package collector 包含所有用于收集和导出系统指标的单独收集器。
package collector

import (
	"fmt"
	"log/slog"
	"os"
	"regexp"
	"strconv"
	"strings"
)

/*
/opt/MegaRAID/MegaCli/MegaCli64 -LDInfo -Lall -aALL：
RAID Level : Primary-1, Secondary-0, RAID Level Qualifier-0" #代表Raid 1
RAID Level : Primary-0, Secondary-0, RAID Level Qualifier-0" #代表Raid 0
RAID Level : Primary-5, Secondary-0, RAID Level Qualifier-3" #代表Raid 5
RAID Level : Primary-1, Secondary-3, RAID Level Qualifier-0" #代表Raid10
从拔盘，到插盘的过程磁盘状态的变化。
Device : Normal|Damage|Rebuild|Normal
Virtual Drive : Optimal|Degraded|Degraded|Optimal
Physical Drive : Online|Failed –> Unconfigured|Rebuild|Online
*/

// Pdlistinfo 物理磁盘信息
type Pdlistinfo struct {
	SlotNumber             string
	DeviceId               string
	MediaErrorCount        int
	OtherErrorCount        int
	PredictiveFailureCount int
	FirmwareState          string
	SASAddress             string
	PdType                 string
}

// Ldlistinfo 逻辑磁盘信息
type Ldlistinfo struct {
	TargetId       string
	Name           string
	RaidLevel      string
	Size           string
	State          string
	NumberOfDrives int
}

// inter 将字符串转换为整数
func inter(str string, logger *slog.Logger) int {
	str = strings.TrimSpace(str)
	i, err := strconv.Atoi(str)
	if err != nil {
		logger.Error("Inter error", "err", err)
	}
	return i
}

// ParseMegaCLIPdLog 解析 MegaCLI 物理磁盘日志文件
func ParseMegaCLIPdLog(filename string, logger *slog.Logger) ([]DiskInfo, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("读取 MegaCLI pdlist 日志失败: %w", err)
	}

	content := string(data)
	sections := strings.Split(content, "\n\n")

	var disks []DiskInfo
	for _, section := range sections {
		if strings.Contains(section, "Enclosure Device ID") {
			disk := DiskInfo{
				Controller:  "MegaRAID Controller",
				ErrorCounts: make(map[string]int),
			}

			lines := strings.Split(section, "\n")
			for _, line := range lines {
				// 提取设备ID和槽位号
				if strings.Contains(line, "Enclosure Device ID") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						if disk.DeviceID == "" {
							disk.DeviceID = strings.TrimSpace(parts[1])
						} else {
							disk.DeviceID = fmt.Sprintf("Enclosure: %s", strings.TrimSpace(parts[1]))
						}
					}
				} else if strings.Contains(line, "Slot Number") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						if disk.DeviceID == "" {
							disk.DeviceID = strings.TrimSpace(parts[1])
						} else {
							disk.DeviceID = fmt.Sprintf("%s, Slot: %s", disk.DeviceID, strings.TrimSpace(parts[1]))
						}
					}
				} else if strings.Contains(line, "Media Error Count") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						count, _ := strconv.Atoi(strings.TrimSpace(parts[1]))
						disk.ErrorCounts["Media Error Count"] = count
					}
				} else if strings.Contains(line, "Other Error Count") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						count, _ := strconv.Atoi(strings.TrimSpace(parts[1]))
						disk.ErrorCounts["Other Error Count"] = count
					}
				} else if strings.Contains(line, "Predictive Failure Count") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						count, _ := strconv.Atoi(strings.TrimSpace(parts[1]))
						disk.ErrorCounts["Predictive Failure Count"] = count
					}
				} else if strings.Contains(line, "Firmware state") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						state := strings.TrimSpace(parts[1])
						// 将固件状态转换为指标
						stateValue := 0 // 0 表示在线
						if !strings.Contains(state, "Online") {
							stateValue = 1 // 1 表示非在线
						}
						disk.ErrorCounts["Firmware State Offline"] = stateValue
					}
				}
			}

			// 如果成功提取了设备ID，则添加到结果中
			if disk.DeviceID != "" {
				disks = append(disks, disk)
			}
		}
	}

	return disks, nil
}

// 旧 ParseMegaCLILdLog 解析 MegaCLI 逻辑磁盘日志文件
func ParseMegaCLILdLog(filename string, logger *slog.Logger) ([]DiskInfo, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("读取 MegaCLI LDInfo 日志失败: %w", err)
	}

	content := string(data)
	sections := strings.Split(content, "\n\n")

	var disks []DiskInfo
	for _, section := range sections {
		if strings.Contains(section, "Virtual Drive") {
			disk := DiskInfo{
				Controller:  "MegaRAID Controller",
				ErrorCounts: make(map[string]int),
			}

			lines := strings.Split(section, "\n")
			for _, line := range lines {
				// 提取目标ID和名称
				if strings.Contains(line, "Virtual Drive") {
					// 使用正则表达式提取目标ID
					re := regexp.MustCompile(`Virtual Drive.*?(\d+)`)
					matches := re.FindStringSubmatch(line)
					if len(matches) > 1 {
						disk.DeviceID = fmt.Sprintf("Virtual Drive: %s", matches[1])
					}
				} else if strings.Contains(line, "Name") && !strings.Contains(line, "Additional") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						name := strings.TrimSpace(parts[1])
						if name != "" && name != "NULL" {
							if disk.DeviceID == "" {
								disk.DeviceID = fmt.Sprintf("Name: %s", name)
							} else {
								disk.DeviceID = fmt.Sprintf("%s, Name: %s", disk.DeviceID, name)
							}
						}
					}
				} else if strings.Contains(line, "Number Of Drives") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						count, _ := strconv.Atoi(strings.TrimSpace(parts[1]))
						disk.ErrorCounts["Number Of Drives"] = count
					}
				}
			}

			// 如果成功提取了设备ID，则添加到结果中
			if disk.DeviceID != "" {
				disks = append(disks, disk)
			}
		}
	}

	return disks, nil
}

// ParseMegaCLILogicDiskLog 解析 MegaCLI 逻辑磁盘日志文件并返回 LogicDiskInfo 结构体
func ParseMegaCLILogicDiskLog(filename string, logger *slog.Logger) ([]LogicDiskInfo, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("读取 MegaCLI LDInfo 日志失败: %w", err)
	}

	content := string(data)
	sections := strings.Split(content, "\n\n")

	var disks []LogicDiskInfo
	for _, section := range sections {
		if strings.Contains(section, "Virtual Drive") {
			disk := LogicDiskInfo{
				Controller: "MegaRAID Controller",
				Info:       make(map[string]string),
			}

			lines := strings.Split(section, "\n")
			for _, line := range lines {
				// 提取目标ID和名称
				if strings.Contains(line, "Virtual Drive") {
					// 使用正则表达式提取目标ID
					re := regexp.MustCompile(`Virtual Drive.*?(\d+)`)
					matches := re.FindStringSubmatch(line)
					if len(matches) > 1 {
						disk.DeviceID = fmt.Sprintf("Virtual Drive: %s", matches[1])
					}
				} else if strings.Contains(line, "Name") && !strings.Contains(line, "Additional") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						name := strings.TrimSpace(parts[1])
						if name != "" && name != "NULL" {
							if disk.DeviceID == "" {
								disk.DeviceID = fmt.Sprintf("Name: %s", name)
							} else {
								disk.DeviceID = fmt.Sprintf("%s, Name: %s", disk.DeviceID, name)
							}
						}
						disk.Info["Name"] = name
					}
				} else if strings.Contains(line, "RAID Level") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						raidLevel := strings.TrimSpace(parts[1])
						disk.RaidLevel = parseMegaCliRaidLevel(raidLevel)
					}
				} else if strings.Contains(line, "Size") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						disk.Size = strings.TrimSpace(parts[1])
					}
				} else if strings.Contains(line, "State") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						disk.State = strings.TrimSpace(parts[1])
					}
				} else if strings.Contains(line, "Number Of Drives") {
					parts := strings.Split(line, ":")
					if len(parts) > 1 {
						count, _ := strconv.Atoi(strings.TrimSpace(parts[1]))
						disk.NumberOfDrives = count
					}
				}
			}

			// 如果成功提取了设备ID，则添加到结果中
			if disk.DeviceID != "" {
				disks = append(disks, disk)
			}
		}
	}

	return disks, nil
}

// parseMegaCliRaidLevel 解析 MegaCLI RAID 级别字符串为标准格式
func parseMegaCliRaidLevel(raidLevel string) string {
	// 示例输入: "Primary-1, Secondary-0, RAID Level Qualifier-0"
	// 示例输出: "RAID1"

	// 使用正则表达式提取主要和次要RAID级别
	primaryRegex := regexp.MustCompile(`Primary-(\d+)`)
	secondaryRegex := regexp.MustCompile(`Secondary-(\d+)`)

	primaryMatch := primaryRegex.FindStringSubmatch(raidLevel)
	secondaryMatch := secondaryRegex.FindStringSubmatch(raidLevel)

	if len(primaryMatch) < 2 || len(secondaryMatch) < 2 {
		return raidLevel // 如果无法解析，则返回原始字符串
	}

	primary, _ := strconv.Atoi(primaryMatch[1])
	secondary, _ := strconv.Atoi(secondaryMatch[1])

	// 根据 MegaCLI 文档中的规则转换 RAID 级别
	switch {
	case primary == 0 && secondary == 0:
		return "RAID0"
	case primary == 1 && secondary == 0:
		return "RAID1"
	case primary == 5 && secondary == 0:
		return "RAID5"
	case primary == 1 && secondary == 3:
		return "RAID10"
	default:
		// 对于其他组合，返回格式化后的字符串
		if secondary == 0 {
			return fmt.Sprintf("RAID%d", primary)
		}
		return fmt.Sprintf("RAID%d%d", primary, secondary)
	}
}
